package com.nf.mvc;

import cn.hutool.core.lang.ClassScanner;
import com.nf.mvc.adapter.RequestMappingHandlerAdapter;
import com.nf.mvc.exception.ExceptionHandlerExceptionResolver;
import com.nf.mvc.mapping.RequestMappingHandlerMapping;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

//这里不需要写WebServlet注解来决定处理哪个地址的请求，由框架使用者去决定
public class DispatcherServlet extends HttpServlet {

    List<HandlerMapping> mappings = new ArrayList<>();
    List<HandlerAdapter> adapters = new ArrayList<>();

    HandlerExceptionResolver exceptionResolver;

    @Override
    public void init(ServletConfig config) throws ServletException {


        String basePackage = config.getInitParameter("basePackage");
        Set<Class<?>> classSet = ClassScanner.scanAllPackage(basePackage, null);

        MvcContext.getMvcContext().setScannedClasses(classSet);

        mappings.add(new RequestMappingHandlerMapping());

        adapters.add(new RequestMappingHandlerAdapter());
        //异常解析器不能直接在声明字段时实例化，因为其构造函数读取了MvcContext扫描到的类
        // 所以实例化要放在扫描工作之后
        exceptionResolver = new ExceptionHandlerExceptionResolver();
    }


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            Object handler = getHandler(req);
            if (handler == null) {
                noHandlerFound(req, resp);
            } else {
                doDispatch(req, resp, handler);
            }
        } catch (Throwable e) {
            System.out.println("mvc框架只处理handler执行过程中出现的Exception异常，非Exception没有处理");
        }
    }


    protected Object getHandler(HttpServletRequest request) throws Exception {
        Object handler = null;
        for (HandlerMapping mapping : mappings) {
            handler = mapping.getHandler(request);
            if (handler != null) {
                break;
            }
        }
        return handler;
    }

    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //利用servlet容器的默认servlet来处理找不到handler的情况
        request.getServletContext().getNamedDispatcher("default").forward(request, response);
    }

    protected void doDispatch(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        HandlerContext handlerContext = HandlerContext.getContext();
        ViewResult viewResult = null;
        try {
            HandlerAdapter adapter = getHandlerAdapter(handler);
            handlerContext.setRequest(req).setResponse(resp);
            viewResult = adapter.handle(req, resp, handler);

        } catch (Exception e) {
            //异常处理的代码
            viewResult = exceptionResolver.resolveException(req, resp, handler, e);
            //异常解析器处理结果为null，通常意味着异常解析器处理不了异常，所以这里继续抛出
            // 这里抛出的异常会被doDispatch方法的调用方法service方法捕获
            if (viewResult == null) {
                throw e;
            }

        } finally {
            handlerContext.clear();
        }
        //如果渲染出了异常，我们的异常解析器是无法处理的
        //我们的异常解析器只处理handle执行过程中出现的异常
        viewResult.render(req, resp);
    }

    protected HandlerAdapter getHandlerAdapter(Object handler) throws Exception {
        for (HandlerAdapter adapter : adapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalStateException("你的mvc没有写完整，这个handler没有adapter可以处理");
    }
}
